home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / vim_src.zip / REGSUB.C < prev    next >
C/C++ Source or Header  |  1993-01-12  |  8KB  |  384 lines

  1. /* vi:ts=4:sw=4
  2.  * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
  3.  *
  4.  * This is NOT the original regular expression code as written by
  5.  * Henry Spencer. This code has been modified specifically for use
  6.  * with the VIM editor, and should not be used apart from compiling
  7.  * VIM. If you want a good regular expression library, get the
  8.  * original code. The copyright notice that follows is from the
  9.  * original.
  10.  *
  11.  * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
  12.  *
  13.  * regsub
  14.  *
  15.  *        Copyright (c) 1986 by University of Toronto.
  16.  *        Written by Henry Spencer.  Not derived from licensed software.
  17.  *
  18.  *        Permission is granted to anyone to use this software for any
  19.  *        purpose on any computer system, and to redistribute it freely,
  20.  *        subject to the following restrictions:
  21.  *
  22.  *        1. The author is not responsible for the consequences of use of
  23.  *                this software, no matter how awful, even if they arise
  24.  *                from defects in it.
  25.  *
  26.  *        2. The origin of this software must not be misrepresented, either
  27.  *                by explicit claim or by omission.
  28.  *
  29.  *        3. Altered versions must be plainly marked as such, and must not
  30.  *                be misrepresented as being the original software.
  31.  *
  32.  * $Log:        regsub.c,v $
  33.  * Revision 1.2  88/04/28  08:11:25  tony
  34.  * First modification of the regexp library. Added an external variable
  35.  * 'reg_ic' which can be set to indicate that case should be ignored.
  36.  * Added a new parameter to regexec() to indicate that the given string
  37.  * comes from the beginning of a line and is thus eligible to match
  38.  * 'beginning-of-line'.
  39.  *
  40.  * Revisions by Olaf 'Rhialto' Seibert, rhialto@cs.kun.nl:
  41.  * Changes for vi: (the semantics of several things were rather different)
  42.  * - Added lexical analyzer, because in vi magicness of characters
  43.  *   is rather difficult, and may change over time.
  44.  * - Added support for \< \> \1-\9 and ~
  45.  * - Left some magic stuff in, but only backslashed: \| \+
  46.  * - * and \+ still work after \) even though they shouldn't.
  47.  */
  48.  
  49. #include "vim.h"
  50. #include "globals.h"
  51. #include "proto.h"
  52.  
  53. #ifdef MSDOS
  54. # define __ARGS(a)    a
  55. #endif
  56.  
  57. /*
  58.  * Short explanation of the tilde: it stands for the previous replacement
  59.  * pattern. If that previous pattern also contains a ~ we should go back
  60.  * a step further... or insert the previous pattern into the current one
  61.  * and remember that.
  62.  * This still does not handle the case where "magic" changes. TODO?
  63.  *
  64.  * On the other hand, this definition is not so useful. We can always retype
  65.  * the previous pattern... especially with command history or in files.
  66.  *
  67.  * It would seem much more useful to remember the previously substituted
  68.  * text. There is generally no other way to get at this. This is useful
  69.  * when you want to do several substitutions on one line, and skip for
  70.  * the second whatever you changed in the first.
  71.  *
  72.  * mool: The last solution is not very useful in combination with the 'g'
  73.  * option, the replacement pattern would get bigger at each replacement.
  74.  * I prefer the original VI method, also for compatibility.
  75.  */
  76. #define TILDE
  77. #define VITILDE
  78. #define CASECONVERT
  79.  
  80. #include <stdio.h>
  81. #include "regexp.h"
  82. #include "regmagic.h"
  83.  
  84. #ifdef LATTICE
  85. # include <sys/types.h>        /* for size_t */
  86. #endif
  87.  
  88. #ifndef CHARBITS
  89. #define UCHARAT(p)      ((int)*(unsigned char *)(p))
  90. #else
  91. #define UCHARAT(p)      ((int)*(p)&CHARBITS)
  92. #endif
  93.  
  94. extern char        *reg_prev_sub;
  95.  
  96. #ifdef CASECONVERT
  97. typedef void *(*fptr) __ARGS((char *, int));
  98. static fptr strnfcpy __ARGS((fptr, char *, char *, int));
  99.  
  100. static fptr do_copy __ARGS((char *, int));
  101. static fptr do_upper __ARGS((char *, int));
  102. static fptr do_Upper __ARGS((char *, int));
  103. static fptr do_lower __ARGS((char *, int));
  104. static fptr do_Lower __ARGS((char *, int));
  105.  
  106.     static fptr
  107. do_copy(d, c)
  108.     char *d;
  109.     int c;
  110. {
  111.     *d = c;
  112.  
  113.     return (fptr)do_copy;
  114. }
  115.  
  116.     static fptr
  117. do_upper(d, c)
  118.     char *d;
  119.     int c;
  120. {
  121.     *d = toupper(c);
  122.  
  123.     return (fptr)do_copy;
  124. }
  125.  
  126.     static fptr
  127. do_Upper(d, c)
  128.     char *d;
  129.     int c;
  130. {
  131.     *d = toupper(c);
  132.  
  133.     return (fptr)do_Upper;
  134. }
  135.  
  136.     static fptr
  137. do_lower(d, c)
  138.     char *d;
  139.     int c;
  140. {
  141.     *d = tolower(c);
  142.  
  143.     return (fptr)do_copy;
  144. }
  145.  
  146.     static fptr
  147. do_Lower(d, c)
  148.     char *d;
  149.     int c;
  150. {
  151.     *d = tolower(c);
  152.  
  153.     return (fptr)do_Lower;
  154. }
  155.  
  156.     static fptr
  157. strnfcpy(f, d, s, n)
  158.     fptr f;
  159.     char *d;
  160.     char *s;
  161.     int n;
  162. {
  163.     while (n-- > 0) {
  164.         f = (fptr)(f(d, *s));        /* Turbo C complains without the typecast */
  165.         if (!*s++)
  166.             break;
  167.         d++;
  168.     }
  169.  
  170.     return f;
  171. }
  172. #endif
  173.  
  174. /*
  175.  - regsub - perform substitutions after a regexp match
  176.  *
  177.  * Returns the size of the replacement, including terminating \0.
  178.  */
  179.     int
  180. regsub(prog, source, dest, copy, magic)
  181.     regexp           *prog;
  182.     char           *source;
  183.     char           *dest;
  184.     int             copy;
  185.     int             magic;
  186. {
  187.     register char  *src;
  188.     register char  *dst;
  189.     register char    c;
  190.     register int    no;
  191.     register int    len;
  192. #ifdef CASECONVERT
  193.     fptr            func = (fptr)do_copy;
  194. #endif
  195. #ifdef VITILDE
  196.     char           *tmp_sub = NULL;
  197. #endif
  198.  
  199.     if (prog == NULL || source == NULL || dest == NULL)
  200.     {
  201.         emsg(e_null);
  202.         return 0;
  203.     }
  204.     if (UCHARAT(prog->program) != MAGIC)
  205.     {
  206.         emsg(e_re_corr);
  207.         return 0;
  208.     }
  209.     src = source;
  210.     dst = dest;
  211.  
  212.     while ((c = *src++) != '\0')
  213.     {
  214.         no = -1;
  215.         if (c == '&' && magic)
  216.             no = 0;
  217.         else if (c == '\\')
  218.         {
  219.             if (*src == '&' && !magic)
  220.             {
  221.                 ++src;
  222.                 no = 0;
  223.             }
  224.             else if ('0' <= *src && *src <= '9')
  225.             {
  226.                 no = *src++ - '0';
  227.             }
  228. #ifdef CASECONVERT
  229.             else if (*src == 'u')
  230.             {
  231.                 src++;
  232.                 func = (fptr)do_upper;
  233.                 continue;
  234.             }
  235.             else if (*src == 'U')
  236.             {
  237.                 src++;
  238.                 func = (fptr)do_Upper;
  239.                 continue;
  240.             }
  241.             else if (*src == 'l')
  242.             {
  243.                 src++;
  244.                 func = (fptr)do_lower;
  245.                 continue;
  246.             }
  247.             else if (*src == 'L')
  248.             {
  249.                 src++;
  250.                 func = (fptr)do_Lower;
  251.                 continue;
  252.             }
  253.             else if (*src == 'e' || *src == 'E')
  254.             {
  255.                 src++;
  256.                 func = (fptr)do_copy;
  257.                 continue;
  258.             }
  259. #endif
  260.         }
  261. #ifdef TILDE
  262.         if ((c == '~' && magic) || (c == '\\' && *src == '~' && !magic))
  263.         {
  264.             if (c == '\\')
  265.                 ++src;
  266.             if (reg_prev_sub)
  267.             {
  268. # ifdef VITILDE
  269.                 /*
  270.                  * We should now insert the previous pattern at
  271.                  * this location in the current pattern, and remember that
  272.                  * for next time... this is very painful to do right.
  273.                  */
  274.                 if (copy)
  275.                 {
  276.                     char           *newsub;
  277.                     int                len;
  278.  
  279. #ifdef DEBUG
  280.                     printf("Old ~: '%s'\r\n", reg_prev_sub);
  281. #endif
  282.                     /* length = len(current) - 1 + len(previous) + 1 */
  283.                     newsub = alloc((unsigned)(strlen(source) + strlen(reg_prev_sub)));
  284.                     if (newsub)
  285.                     {
  286.                         /* copy prefix */
  287.                         len = (src - source) - 1;    /* not including ~ */
  288.                         if (!magic)
  289.                             len--;                    /* back off \ */
  290.                         strncpy(newsub, source, (size_t)len);
  291.                         /* interpolate tilde */
  292.                         strcpy(newsub + len, reg_prev_sub);
  293.                         /* copy postfix */
  294.                         strcat(newsub + len, src);
  295.  
  296.                         if (tmp_sub)
  297.                             free(tmp_sub);
  298.                         tmp_sub = newsub;
  299.                         source = newsub;
  300.                         src = newsub + len;
  301.                     }
  302. #ifdef DEBUG
  303.                     printf("New  : '%s'\r\n", newsub);
  304.                     printf("Todo : '%s'\r\n", src);
  305. #endif
  306.                 }
  307.                 else
  308.                 {
  309.                     dst += regsub(prog, reg_prev_sub, dst, copy, magic) - 1;
  310.                 }
  311. # else /* no VITILDE */
  312.                 if (copy)
  313.                 {
  314. #  ifdef CASECONVERT
  315.                     func = strnfcpy(func, dst, reg_prev_sub, ((unsigned)~0)>>1);
  316. #  else
  317.                     (void) strcpy(dst, reg_prev_sub);
  318. #  endif
  319.                 }
  320.                 dst += strlen(reg_prev_sub);
  321. # endif /* def VITILDE */
  322.             }
  323.         }
  324.         else
  325. #endif  /* def TILDE */
  326.         if (no < 0)           /* Ordinary character. */
  327.         {
  328.             if (c == '\\')
  329.                 c = *src++;
  330.             if (copy)
  331.             {
  332. #ifdef CASECONVERT
  333.                 func = (fptr)(func(dst, c));
  334.                             /* Turbo C complains without the typecast */
  335. #else
  336.                 *dst = c;
  337. #endif
  338.             }
  339.             dst++;
  340.         }
  341.         else if (prog->startp[no] != NULL && prog->endp[no] != NULL)
  342.         {
  343.             len = prog->endp[no] - prog->startp[no];
  344.             if (copy)
  345.             {
  346. #ifdef CASECONVERT
  347.                 func = strnfcpy(func, dst, prog->startp[no], len);
  348. #else
  349.                 (void) strncpy(dst, prog->startp[no], len);
  350. #endif
  351.             }
  352.             dst += len;
  353.             if (copy && len != 0 && *(dst - 1) == '\0') { /* strncpy hit NUL. */
  354.                 emsg(e_re_damg);
  355.                 goto exit;
  356.             }
  357.         }
  358.     }
  359.     if (copy)
  360.         *dst = '\0';
  361.  
  362. #ifdef TILDE
  363. # ifdef VITILDE
  364.     if (copy) {
  365.         if (reg_prev_sub)
  366.             free(reg_prev_sub);
  367.         if (tmp_sub)
  368.             reg_prev_sub = tmp_sub;        /* tmp_sub == source */
  369.         else
  370.             reg_prev_sub = strsave(source);
  371.     }
  372. # else
  373.     if (copy) {
  374.         if (reg_prev_sub)
  375.             free(reg_prev_sub);
  376.         reg_prev_sub = strsave(dest);
  377.     }
  378. # endif
  379. #endif
  380.  
  381. exit:
  382.     return (int)((dst - dest) + 1);
  383. }
  384.